﻿#pragma once
#pragma pack(push, 1)

typedef struct _BootSector
{
	char szJmp[3];					//跳转指令
	char szTag[8];					//系统标识符："NTFS    "
	uint16_t uSectorSize;			//每个扇区的字节数
	uint8_t uClusterSectors;		//每个簇的扇区数
	char szReserved0[7];			//保留
	char cMediaDesc;				//介质描述
	char szReserved1[2];			//保留
	uint16_t uHSectors;				//每磁头扇区数
	uint16_t uCSectors;				//每柱面磁头数
	uint32_t uOffsetSectors;		//隐含扇区（从MBR到DBR的扇区总数）
	char szReserved2[4];			//保留
	char szFixed0[4];				//一般是 80 00 80 00
	uint64_t uTotalSectors;			//扇区总数，即分区大小
	uint64_t uMFTOffset;			//$MFT的开始簇号
	uint64_t uMFTMirrOffset;		//$MFTMirr的开始簇号
	uint32_t uMFTRecordClusters;	//每个MFT记录的簇数
	uint32_t uIndexRecordClusters;	//每个索引记录的簇
	uint64_t uPartitionNum;			//分区序列号
	uint32_t uCheckSum;				//0
	char szBootCode[426];			//引导程序
	uint16_t uSignature;			//固定为55 AA
}BootSector, *PBootSector;

//文件记录头（48字节）//50个字节
typedef struct _FileRecordHead
{
	char szSignature[4];			//签名，固定为"FILE"
	uint16_t uFixupOffset;			//更新数组的偏移
	uint16_t uFixupEntries;			//更新数组记录数
	uint64_t uLogFileSeqNum;		//日志文件序列号（每次记录被修改，都将导致该序列号加1）
	uint16_t uIncSeqNum;			//序列号（记录本文件记录被重复使用的次数，每次文件删除时加1，跳过0值，如果为0，则保持为0）
	uint16_t uHardLinkCount;		//硬连接数，只出现在基本文件记录中，目录所含项数要使用到它
	uint16_t uStartAttrOffset;		//第一个属性流的偏移地址
	uint16_t uFlag;					//标志字节，1表示记录使用中，2表示记录为目录
	uint32_t uEntriesUsedSize;		//文件记录实际大小（填充到8字节，即以8字节为边界）
	uint32_t uEntriesAllocSize;		//文件记录分配大小（填充到8字节，即以8字节为边界）
	uint64_t uFileRefToBaseRecord;	//所对应的基本文件记录的文件参考号（扩展文件记录中使用，基本文件记录中为0，在基本文件记录的属性列表0x20属性存储中扩展文件记录的相关信息）
	uint16_t uNextAttrId;			//下一个属性号
	uint16_t uFixupCodeXP;			//边界，文件记录使用的两个扇区的最后两个字节的值，windows xp中使用
	uint32_t uMFTNumber;			//在$MFT的文件记录号
	uint16_t uFixupCode;			//边界，文件记录使用的两个扇区的最后两个字节的值
}FileRecordHead, *PFileRecordHead;

//属性头公共部分（常驻属性和非常驻属性共有部分）
typedef struct _AttrHead
{
	uint32_t uType;				//属性类型0~4
	uint32_t uLength;			//属性长度，8的整数倍4~8
	uint8_t uNonResident;		//是否为常驻属性，0表示常驻，1表示非常驻8~9
	uint8_t uAttrNameLen;		//属性名长度9~10
	uint16_t uAttrNameOffset;	//属性内容的偏移10~12
	uint16_t uFlag;				//标志，如压缩、加密、稀疏等12~14
}AttrHead, *PAttrHead;

//常驻属性的属性头（24字节）
typedef struct _ResidentAttrHead : public AttrHead
{
	uint16_t uTag;				//标识
	uint32_t uAttrBodyLen;		//属性体长度
	uint16_t uAttrBodyStart;	//属性体开始位置
	uint8_t uIndexFlag;			//索引标志
	uint8_t uPadding;			//填充
}ResidentAttrHead, *PResidentAttrHead;

//非常驻属性的属性头(64字节) ： 公共 14， 这里是50
typedef struct _NonResidentAttrHead : public AttrHead
{
	uint16_t uAttrId;			//属性ID 0~2 
	uint64_t uBeginVCN;			//起始虚拟簇号 2~10
	uint64_t uEndVCN;			//结束虚拟簇号 10~18 
	uint16_t uDataRunOffset;	//DataRun的偏移地址 18~20
	uint16_t uCompress;			//压缩单位大小，2的N次方 20~22
	uint32_t uReserved;			//保留 22~26
	uint64_t uAttrAllocSize;	//属性分配大小 26~34
	uint64_t uAttrUsedSize;		//属性实际大小 34~42
	uint64_t uAttrOrgSize;		//属性原始大小 42~50
}NonResidentAttrHead, *PNonResidentAttrHead;

//标准信息属性的属性体（72字节）
typedef struct _StandardInfoAttrBody
{
	uint64_t uCreateTime;			//文件创建时间
	uint64_t uModifyTime;			//文件修改时间
	uint64_t uMFTTime;				//MFT变化时间
	uint64_t uVisitTime;			//文件访问时间
	uint32_t uAttribute;			//文件属性
	uint32_t uMaxVersion;			//文件所允许的最大版本号（0表示未使用）
	uint32_t uVersion;				//文件的版本号
	uint32_t uClassId;				//类ID（一个双向的类索引）
	uint32_t uOwnerId;				//所有者ID
	uint32_t uSecureId;				//安全ID
	uint64_t uFileSize;				//本文件所占用的字节数，它是文件所有流占用的总字节数，为0表示未使用磁盘配额
	uint64_t uUpdateSN;				//更新系列号（USN），是到文件$USNJRNL的一个直接的索引，为0表示USN日志未使用
}StandardInfoAttrBody, *PStandardInfoAttrBody;

//文件名属性的属性体
typedef struct _FileNameAttrBody
{
	uint64_t uParentRecordNum;		//父目录的文件参考号（前6个字节48位为父目录的文件记录号）
	uint64_t uCreateTime;			//文件创建时间
	uint64_t uModifyTime;			//文件修改时间
	uint64_t uMFTTime;				//最后一次MFT更新时间
	uint64_t uVisitTime;			//最后一次访问时间
	uint64_t uAllocSize;			//文件分配大小
	uint64_t uRealSize;				//文件实际大小
	uint32_t uFlag;					//标志，如目录、压缩、隐藏等
	uint32_t uEAS;					//用于EAS和重解析点
	uint8_t uNameLen;				//以字符计的文件名长度，每字符占用字节数由下一字节命名空间确定，一个字节长度，所以文件名最长255字节。
	uint8_t uNamespace;				//文件名命名空间
//	char szFileName[0];				//文件名和填充
}FileNameAttrBody, *PFileNameAttrBody;

//属性列表项（属性列表属性（0X20）内容）20字节
typedef struct _AttrListItem
{
	uint32_t uAttrType;				//属性类型 4
	uint16_t uItemSize;				//本项长度 4-6
	uint8_t uNameLen;				//名称长度 6-7
	uint8_t uNameOffset;			//名称偏移 7-8
	uint64_t uStartVCN;				//起始虚拟簇号 8-16
	uint64_t uMFTNumber;			//属性所属文件记录的MTF参考号 16-24
	uint16_t uAttrId;				//属性ID 
//	char szName[0];					//如果uNameLen大于0，这里存放名称
}AttrListItem, *PAttrListItem;

//索引根（索引根属性（0X90属性）内容）
typedef struct _IndexRoot
{
	uint32_t uAttrType;				//属性类型
	uint32_t uSortRule;				//排序规则
	uint32_t uIndexBufferSize;		//每个索引缓冲区的分配大小（字节数）
	uint8_t uIndexBufferCluster;	//每个索引缓冲区的簇数
	char szPadding[3];				//填充
}IndexRoot, *PIndexRoot;

//索引头（索引根属性（0X90属性）内容）
typedef struct _IndexHead
{
	uint32_t uIndexItemOffset;		//第一个索引项的偏移
	uint32_t uIndexItemsSize;		//索引项的总大小
	uint32_t uIndexItemsAlloc;		//索引项分配的大小
	uint8_t uFlag;					//标志位，此值可能是以下值之一：0x00小目录(数据存放在根节点的数据区中)；0x01大目录(需要目录项存储区和索引项位图)
	char szPadding[3];				//填充
}IndexHead, *PIndexHead;

//标准索引头（索引分配属性（0xA0属性）内容）
typedef struct _StandardIndexHead
{
	char szSignature[4];			//签名，固定为"INDX"
	uint16_t uUSNOffset;			//更新序列号偏移
	uint16_t uUSNSize;				//更新序列号和更新数组大小
	uint64_t uLogFileSN;			//日志文件序列号
	uint64_t uIndexCacheVCN;		//本索引缓冲区在索引分配中的VCN
	uint32_t uIndexItemOffset;		//索引项的偏移（相对于当前位置）
	uint32_t uIndexItemsSize;		//索引项的总大小
	uint32_t uIndexItemsAlloc;		//索引项分配的大小
	uint8_t uHasLeafNode;			//置1表示有子节点
	char szPadding[3];				//填充
	uint16_t uUSN;					//更新序列号
//	char szUSNArray[0];				//更新序列数组		//开始于第42字节
}StandardIndexHead, *PStandardIndexHead;

//标准索引项（索引分配属性（0xA0属性）内容）
typedef struct _StandardIndexItem
{
	uint64_t uMFTNumber;			//文件的MFT参考号 0~8
	uint16_t uIndexItemSize;		//索引项的大小 8~10
	uint16_t uFileNameAttrBodySize;	//文件名属性体的大小(文件名偏移) 10~12
	uint16_t uIndexFlag;			//索引标志（为1表示这个索引项包含子节点；为2表示这是最后一个项）12~14
	char szPadding[2];				//填充 14~16
	uint64_t uParentMFTNumber;		//父目录的MFT文件参考号 16~24
	uint64_t uCreateTime;			//文件创建时间 24~32
	uint64_t uModifyTime;			//最后修改时间 32~40
	uint64_t uMFTTime;				//文件记录最后修改时间 40~48
	uint64_t uVisitTime;			//最后访问时间 48~56
	uint64_t uAllocSize;			//文件分配大小 56~64
	uint64_t uRealSize;				//文件实际大小 
	uint32_t uFlag;					//标志，如目录、压缩、隐藏等
	uint32_t uEAS;					//用于EAS和重解析点
	uint8_t uFileNameSize;			//文件名长度
	uint8_t uFileNamespace;			//文件命名空间
//  char szFileName[0];				//文件名和填充
}StandardIndexItem, *PStandardIndexItem;

#pragma pack(pop)
